#! /usr/bin/env python """Different ways to invoke another program from within Python "CallingAnExternalProgram.py" There are several ways to call an external program from within Python. This is a demonstration of two: simple, without much control over I/O versus tight control. """ import os, sys, popen2 class ExecutionFailed (Exception): """Running the external program resulted in an unexpected return code""" def __str__(self): return self.__doc__ class CallingAnExternalProgram: programName = "python -i" #programName = "false" #programName = "ls" # Enter these commands into Python's interpretor manually, # just to see what happens: script = ("a = 1", "a += 3", "print a") #script = ("a = 1", "a += 3", "print bluecheese_withSPAM") expectPrompt = ">>> " def SimpleProgramExecution(self): """Most basic approach to invoke an external program This is without regard for tracking output or feeding input, so long as it gets done. For any interactivity of input or output beyond an all-or-nothing approach, explore popen2 module and its family of classes and functions. (see below!) Note that there is no clean way to hide stdout/stderr output from os.system(), hence the next method that calls popen()... (To actually parse output with os.system(), you must remap file descriptors prior to making the function call.) """ # Beyond the one statement below that calls "os.system()", # all other lines within this method are just to populate # "commandLine" gracefully. print "\n\n\tExecuting a single command line as Unix-style pipeline:\n\n" script = None for statement in self.script: if script: script = "%s; %s" % (script, statement) else: script = statement commandLine = "echo '%s'| %s" % (script, self.programName) print "Running:", commandLine sys.stdout.flush() # optional; try removing, then re-run! # This is all that really interests us: exitStatus = os.system(commandLine) if exitStatus != 0: # Exit status: zero means success, non-zero might be "errno" raise ExecutionFailed, exitStatus def ProgramExecutionWithIO(self): """Provide interactive I/O control over program called. If you have Cygwin installed, you have the complete Python documentation available to you, include standard modules. Please see: file:///c:/cygwin/usr/share/doc/python-2.3.3/html/lib/module-popen2.html For the non-Cygwin installation, see: START -> All Programs -> Python 2.3 -> Python Manuals Select "Global Module Index" then "popen2" (Yes, use "popen2" manual even though we're calling "popen4" !!!) """ print "\n\n\tInteracting with external program:\n\n" commandLine = self.programName print "Running:", commandLine process = popen2.Popen4(commandLine) childStdin = process.tochild childStdout = process.fromchild # We know Python interpretor interface has three lines of headers: for header in xrange(3): ignore = childStdout.readline() #print ignore for line in self.script: print "Executing:", line command = line + "\n" childStdin.write(command) childStdin.flush() childStdout.flush() prompt = childStdout.read(len(self.expectPrompt)) if prompt != self.expectPrompt: raise "Unexpected results", prompt childStdin.close() results = childStdout.readlines() # We happen to know that that the n-1 line of output will be a # prompt from Python's interpretor, so clean-up the output. answer = results[:-2] print "Answer follows:" for line in answer: print line if results[-2] != self.expectPrompt: print results[-2] childStdout.close() exitStatus = process.wait() if exitStatus != 0: # Exit status: zero means success, non-zero might be "errno" raise ExecutionFailed, results if __name__ == "__main__": execute = CallingAnExternalProgram() execute.SimpleProgramExecution() execute.ProgramExecutionWithIO() #End.